//
// Created by HP on 2022/1/22.
//

#include "keyboard_movement_controller.h"

#include <cmath>

namespace lve {

    void KeyboardMovementController::moveInPlaneXZ(
            GLFWwindow *window, float dt, LveGameObject &gameObject) {
        glm::vec3 rotate{0};
        // 计算键盘
        if (glfwGetKey(window, keys.lookRight) == GLFW_PRESS) rotate.y += 1.f;
        if (glfwGetKey(window, keys.lookLeft)  == GLFW_PRESS) rotate.y -= 1.f;
        if (glfwGetKey(window, keys.lookUp)    == GLFW_PRESS) rotate.x += 1.f;
        if (glfwGetKey(window, keys.lookDown)  == GLFW_PRESS) rotate.x -= 1.f;

        // 计算鼠标
        double xPos, yPos;
        auto lveWindow = reinterpret_cast<LveWindow*>(glfwGetWindowUserPointer(window));
        lveWindow->getCursorPos(&xPos, &yPos);
        glm::vec2 newCursor{xPos, yPos};
        auto cursorMove = newCursor - cursor;
        if (cursorMove.x > std::numeric_limits<float>::epsilon() ||
            cursorMove.x < -std::numeric_limits<float>::epsilon()) {
            rotate.y += cursorMove.x * 300.f;
        }
        if (cursorMove.y > std::numeric_limits<float>::epsilon() ||
            cursorMove.y < -std::numeric_limits<float>::epsilon()) {
            rotate.x -= cursorMove.y * 300.f;
        }

        cursor = newCursor;

        if (glm::dot(rotate, rotate) > std::numeric_limits<float>::epsilon()) {
            gameObject.transform.rotation += lookSpeed * dt * rotate;
        }
        // 防止在一个方向上不断旋转导致溢出
        gameObject.transform.rotation.y = glm::mod(gameObject.transform.rotation.y, glm::two_pi<float>());

        const float c2 = glm::cos(gameObject.transform.rotation.x);
        const float s2 = glm::sin(gameObject.transform.rotation.x);
        const float c1 = glm::cos(gameObject.transform.rotation.y);
        const float s1 = glm::sin(gameObject.transform.rotation.y);
        const float x = c2 * s1;
        const float y = -s2;
        const float z = c1 * c2;
        const glm::vec3 forwardDir{x, y, z};
        const glm::vec3 rightDir{z, 0.f, -x};
        const glm::vec3 upDir{0.f, -1.f, 0.f};

        glm::vec3 moveDir{0.f};
        if (glfwGetKey(window, keys.moveForward)  == GLFW_PRESS) moveDir += forwardDir;
        if (glfwGetKey(window, keys.moveBackward) == GLFW_PRESS) moveDir -= forwardDir;
        if (glfwGetKey(window, keys.moveRight)    == GLFW_PRESS) moveDir += rightDir;
        if (glfwGetKey(window, keys.moveLeft)     == GLFW_PRESS) moveDir -= rightDir;
        if (glfwGetKey(window, keys.moveUp)       == GLFW_PRESS) moveDir += upDir;
        if (glfwGetKey(window, keys.moveDown)     == GLFW_PRESS) moveDir -= upDir;

        if (glm::dot(moveDir, moveDir) > std::numeric_limits<float>::epsilon()) {
            gameObject.transform.translation += moveSpeed * dt * glm::normalize(moveDir);
        }
    }

}